using System.Collections.Generic;
using System.Threading;
using LogSystem;
using Pathfinding;
using UnityEngine.Rendering;
using UnityEngine;
using Yoozoo.Core.Extensions.CSharp;
using Yoozoo.Core.Extensions.Engine;
using Yoozoo.Mars.Got;

namespace Yoozoo.Gameplay.City
{
    public class CityRealAiRoomManager : CityRealAiContainerManagerBase
    {
        public int BuildIndex { get; }
        
        public int AreaId { get; }
        
        /// <summary>
        /// 是否为拖拽状态
        /// </summary>
        public bool IsDragState { get; private set; }

        /// <summary>
        /// 进门点
        /// </summary>
        public Vector3 InRoomLocalPos { get; private set; }
        
        /// <summary>
        /// 出门点
        /// </summary>
        public Vector3 OutRoomLocalPos { get; private set; }
        
        /// <summary>
        /// 消失/出现点
        /// </summary>
        public Vector3 HidePointLocalPos { get; private set; }
        
        /// <summary>
        /// 进门点2
        /// </summary>
        public Vector3 InRoomLocalPos2 { get; private set; }
        
        /// <summary>
        /// 出门点2
        /// </summary>
        public Vector3 OutRoomLocalPos2 { get; private set; }

        /// <summary>
        /// 路点
        /// </summary>
        private List<Vector3> _movePointLocalPosList;

        private List<PointNode> _movePointNodeList;

        /// <summary>
        /// 出生点
        /// </summary>
        private List<Vector3> _birthPointLocalPosList;

        private int _maxAreaNpcNum;

        private int _curAreaNpcNum;

        /// <summary>
        /// 本房间出生的Npc数量
        /// </summary>
        public int RoomNpcNum { get; private set; }

        /// <summary>
        /// 房间内是否满员 (会判断排队人数)
        /// </summary>
        public virtual bool IsFull
        {
            get
            {
                if (_maxAreaNpcNum <= 0)
                {
                    return false;
                }

                if (_waitQueue.Count > 0)
                {
                    return true;
                }

                return _curAreaNpcNum >= _maxAreaNpcNum;
            }
        }

        /// <summary>
        /// 房间内是否真实满员 (不会判断排队人数)
        /// </summary>
        public virtual bool IsRealFull
        {
            get
            {
                if (_maxAreaNpcNum <= 0)
                {
                    return false;
                }

                return _curAreaNpcNum >= _maxAreaNpcNum;
            }
        }

        /// <summary>
        /// 房间满员之后是否可以排队
        /// </summary>
        public bool IsCanWait
        {
            get
            {
                if (_maxAreaNpcNum <= 0)
                {
                    return false;
                }

                return _waitQueue.Count < _waitPointInfoList.Count;
            }
        }

        /// <summary>
        /// 是否渲染npc
        /// </summary>
        public bool rendererNpcEnabled => !(CityRealAiManager.GetInstance().RoofShowState &&
                                            CityRealAiManager.GetInstance().LimitShowState);

        public override bool IsLoadComplete
        {
            get
            {
                foreach (var keyValuePair in NpcTypeCtrlDic)
                {
                    foreach (var subKeyValuePair in keyValuePair.Value)
                    {
                        if (!subKeyValuePair.Value.IsLoadComplete)
                        {
                            return false;
                        }
                    }
                }

                return true;
            }
        }

        /// <summary>
        /// 排队点
        /// </summary>
        private List<Vector3> _waitPointPosList;

        private List<Vector3> _waitPointRotList;

        /// <summary>
        /// 排队点数据
        /// </summary>
        protected List<CityRealAiEventPointInfo> _waitPointInfoList;
        
        /// <summary>
        /// 排队队列
        /// </summary>
        protected List<CityRealAiNpcController> _waitQueue;
        public int WaitQueueCount => _waitQueue.Count;

        /// <summary>
        /// 多队列排队点
        /// </summary>
        private List<List<Vector3>> _multiWaitPointVecPosList;
        private List<List<Vector3>> _multiWaitPointVecRotList;
        /// <summary>
        /// 多队列排队点位
        /// </summary>
        protected List<List<CityRealAiEventPointInfo>> _multiWaitPointVecPointInfoList;

        /// <summary>
        /// npc营业时timeline跳转到房间附近时的点位。
        /// </summary>
        protected List<Vector3> _businessNpcJumpToRoomPointVecPosList;
        protected List<Vector3> _businessNpcJumpToRoomPointVecRotList;
        /// <summary>
        /// 多队列排队队列
        /// </summary>
        protected List<List<CityRealAiNpcController>> _multiWaitVecQueue;
        public List<List<CityRealAiNpcController>> MultiWaitVecQueue=>_multiWaitVecQueue;
        
        /// <summary>
        /// 正在前往自己房间的NPC
        /// </summary>
        private List<CityRealAiNpcController> _moveToSelfList;

        private int _roomState;
        /// <summary>
        /// 通用房间事件: 建造升级
        /// </summary>
        private Dictionary<int, CityRealAiRoomEventConfig> _roomCommonEventConfigDic;
        /// <summary>
        /// //根据房间id，从City_ai_roomevent中获取事件配置
        /// </summary>
        private Dictionary<int, CityRealAiRoomEventConfig> _roomEventConfigDic;
        
        /// <summary>
        /// 同一种触发时机重复触发可以多次引发NPC事件
        /// key = trigger event   subKey = index   subValue = roomEventInfo
        /// </summary>
        private Dictionary<CityRealRoomStateChangeEvent, Dictionary<int, CityRealAiRoomEventInfo>> _currentRoomEventDic;
        
        /// <summary>
        /// 通过NPC尝试触发一次事件的过程只能存在一个，即可以触发同一种事件，但是一次只能触发一个。
        /// key city_ai_roomevent.room_state
        /// subKey = parameterKey = city_ai_roomevent.event_condition.(split(';')[index].split('=')[0])
        /// subValue = parameterValue = city_ai_roomevent.event_condition.(split(';')[index].split('=')[1])
        /// </summary>
        private Dictionary<int, Dictionary<string, RoomParameterInfo>> _stateTriggerProcessParameterDic;
        
        // key city_ai_roomevent.event_condition.(split(';')[index].split('=')[0])
        // value city_ai_roomevent.room_state list
        private Dictionary<string, List<int>> _parameterKeyIndex;
        
        // 是否存在特殊学习状态
        private bool _isExistLecture;

        /// <summary>
        /// 缓存所有的垃圾交互点，便于随机
        /// </summary>
        private List<CityRealAiEventPointInfo> _cacheRubbishList;

        /// <summary>
        /// 缓存所有的修理交互点，便于随机
        /// </summary>
        private List<CityRealAiEventPointInfo> _cacheFixList;

        public CityRealAiRoomManager(int containerId, int buildIndex, int areaId) : base(containerId)
        {
            BuildIndex = buildIndex;
            AreaId = areaId;
            _movePointLocalPosList = new List<Vector3>();
            _movePointNodeList = new List<PointNode>();
            _birthPointLocalPosList = new List<Vector3>();
            _waitPointPosList = new List<Vector3>();
            _waitPointRotList = new List<Vector3>();
            _waitPointInfoList = new List<CityRealAiEventPointInfo>();
            _waitQueue = new List<CityRealAiNpcController>();
            _multiWaitPointVecPosList = new List<List<Vector3>>();
            _multiWaitPointVecRotList = new List<List<Vector3>>();
            _multiWaitPointVecPointInfoList = new List<List<CityRealAiEventPointInfo>>();
            _businessNpcJumpToRoomPointVecPosList = new List<Vector3>();
            _businessNpcJumpToRoomPointVecRotList = new List<Vector3>();
            _multiWaitVecQueue = new List<List<CityRealAiNpcController>>();
            _moveToSelfList = new List<CityRealAiNpcController>();
            _cacheRubbishList = new List<CityRealAiEventPointInfo>();
            _cacheFixList = new List<CityRealAiEventPointInfo>();
            
            _roomCommonEventConfigDic = _cfgMgr.GetRoomEventConfigs(CityRealAiConst.CommonRoomEventId);
            
            _roomEventConfigDic = _cfgMgr.GetRoomEventConfigs(containerId);
            if (_roomCommonEventConfigDic != null)
            {
                _currentRoomEventDic = new Dictionary<CityRealRoomStateChangeEvent, Dictionary<int, CityRealAiRoomEventInfo>>();
                foreach (var keyValuePair in _roomCommonEventConfigDic)
                {
                    var roomEventCfg = keyValuePair.Value;
                    if (!string.IsNullOrEmpty(roomEventCfg.event_condition))
                    {
                        UpdateStateParameter(roomEventCfg.room_state, roomEventCfg.event_condition);
                    }
                }
            }
            if (_roomEventConfigDic != null)
            {
                if (_currentRoomEventDic == null)
                {
                    _currentRoomEventDic = new Dictionary<CityRealRoomStateChangeEvent, Dictionary<int, CityRealAiRoomEventInfo>>();
                }
                foreach (var keyValuePair in _roomEventConfigDic)
                {
                    var roomEventCfg = keyValuePair.Value;
                    if (!string.IsNullOrEmpty(roomEventCfg.event_condition))
                    {
                        UpdateStateParameter(roomEventCfg.room_state, roomEventCfg.event_condition);
                    }
                    UpdateExistLecture(roomEventCfg.room_state);//是否有存在讲课
                } 
            }
        }

        private void UpdateStateParameter(int changeEvent, string parameter)
        {
            if (string.IsNullOrEmpty(parameter))
            {
                return;
            }
            
            if (_stateTriggerProcessParameterDic == null)
            {
                _stateTriggerProcessParameterDic = new Dictionary<int, Dictionary<string,RoomParameterInfo>>();
                _parameterKeyIndex = new Dictionary<string, List<int>>();
            }
            
            var split = parameter.Split(';');
            if (split.Length <= 0)
            {
                return;
            }

            if (!_stateTriggerProcessParameterDic.TryGetValue(changeEvent, out var parameterDic))
            {
                parameterDic = new Dictionary<string, RoomParameterInfo>();
                _stateTriggerProcessParameterDic.Add(changeEvent, parameterDic);
            }

            for (int i = 0; i < split.Length; i++)
            {
                var tempSplit = split[i].Split('=');
                if (tempSplit.Length < 2)
                {
                    continue;
                }

                var parameterKey = tempSplit[0];
                if (!parameterDic.ContainsKey(parameterKey))
                {
                    var parameterValue = tempSplit[1];
                    int.TryParse(parameterValue, out var paramterValueInt);
                    var parameterInfo = new RoomParameterInfo(paramterValueInt);
                    parameterDic.Add(parameterKey, parameterInfo);
                }

                if (!_parameterKeyIndex.TryGetValue(parameterKey, out var stateList))
                {
                    stateList = new List<int>();
                    _parameterKeyIndex.Add(parameterKey, stateList);
                }
                stateList.Add(changeEvent);
            }
        }

        private void UpdateExistLecture(int roomState)
        {
            if (!_isExistLecture)
            {
                if (roomState == (int)CityRealRoomStateChangeEvent.BeforeLecture)
                {
                    _isExistLecture = true;
                }
            }
        }

        public void SetupRoomRoot(Transform root)
        {
            RoomRootTran = root;
            foreach (var keyValuePair in GoodsCtrlDic)
            {
                keyValuePair.Value.UpdateGoods();
            }
        }

        public void SetupInRoomPoint(Vector3 inRoomPointTrans)
        {
            InRoomLocalPos = inRoomPointTrans;
            AddMovePoint(inRoomPointTrans);
        }

        public void SetupOutRoomPoint(Vector3 outRoomPointTrans)
        {
            OutRoomLocalPos = outRoomPointTrans;
            AddMovePoint(outRoomPointTrans);
        }

        public void SetupHidePoint(Vector3 hidePointTrans)
        {
            HidePointLocalPos = hidePointTrans;
            AddMovePoint(hidePointTrans);
        }

        public void SetupInRoomPoint2(Vector3 inRoomPointTrans)
        {
            InRoomLocalPos2 = inRoomPointTrans;
            AddMovePoint(inRoomPointTrans);
        }
        
        public void SetupOutRoomPoint2(Vector3 outRoomPointTrans)
        {
            OutRoomLocalPos2 = outRoomPointTrans;
            AddMovePoint(outRoomPointTrans);
        }

        public void SetupMaxAreaNpcNum(int maxAreaNpcNum)
        {
            _maxAreaNpcNum = maxAreaNpcNum;
        }

        public void AddMovePoint(Vector3 movePoint)
        {
            if (!_movePointLocalPosList.Contains(movePoint))
            {
                _movePointLocalPosList.Add(movePoint);
            }
        }

        public void AddBirthPoint(Vector3 birthPoint)
        {
            _birthPointLocalPosList.Add(birthPoint);
            AddMovePoint(birthPoint);
        }

        public void AddWaitPoint(Vector3 waitPointPos, Vector3 waitPointRot)
        {
            _waitPointPosList.Add(waitPointPos);
            _waitPointRotList.Add(waitPointRot);
            var waitPointInfo = new CityRealAiEventPointInfo();
            _waitPointInfoList.Add(waitPointInfo);
        }

        public void AddMultiWaitPoint(int vecIndex, Vector3 waitPointPos, Vector3 waitPointRot)
        {
            if (vecIndex >= _multiWaitPointVecPosList.Count)
            {
                _multiWaitPointVecPosList.Add(new List<Vector3>());
                _multiWaitPointVecRotList.Add(new List<Vector3>());
                _multiWaitPointVecPointInfoList.Add(new List<CityRealAiEventPointInfo>());
                _multiWaitVecQueue.Add(new List<CityRealAiNpcController>());
            }

            List<Vector3> posList = _multiWaitPointVecPosList[vecIndex];
            List<Vector3> rotList = _multiWaitPointVecRotList[vecIndex];
            List<CityRealAiEventPointInfo> pointInfoList = _multiWaitPointVecPointInfoList[vecIndex];
            posList.Add(waitPointPos);
            rotList.Add(waitPointRot);
            pointInfoList.Add(new CityRealAiEventPointInfo());
            
            AddMovePoint(waitPointPos);
        }

        public void AddBusinessNpcJumpToRoomPoint(Vector3 jumpPos, Vector3 jumpRot)
        {
            _businessNpcJumpToRoomPointVecPosList.Add(jumpPos);
            _businessNpcJumpToRoomPointVecRotList.Add(jumpRot);
            
            AddMovePoint(jumpPos);
        }
        
        public void AddRubbishGoods(CityRealAiEventPointInfo eventInfo)
        {
            _cacheRubbishList.Add(eventInfo);
        }

        public void AddFixGoods(CityRealAiEventPointInfo eventInfo)
        {
            _cacheFixList.Add(eventInfo);
        }

        public Vector3 GetRandomBirthLocalPos()
        {
            if (_birthPointLocalPosList.Count <= 0)
            {
                return HidePointLocalPos;
            }
            var index = Random.Range(0, _birthPointLocalPosList.Count);
            return _birthPointLocalPosList[index];
        }

        private int _jumpToRoomPointIndex = 0;
        
        public Vector3 GetNpcJumpToRoomPos()
        {
            if (_businessNpcJumpToRoomPointVecPosList.Count <= _jumpToRoomPointIndex)
            {
                return InRoomLocalPos;
            }

            var result = _businessNpcJumpToRoomPointVecPosList[_jumpToRoomPointIndex];
            _jumpToRoomPointIndex++;
            return result;
        }

        public Vector3 GetNpcJumpToRoomRot()
        {
            if (_businessNpcJumpToRoomPointVecRotList.Count <= _jumpToRoomPointIndex)
            {
                return new Vector3(0, 45, 0);
            }

            return _businessNpcJumpToRoomPointVecRotList[_jumpToRoomPointIndex];
        }
        

        public CityRealAiEventPointInfo GetWaitPointInfo(int queueIndex, int index, int eventId)
        {
            if (queueIndex < 0)
            {
                // 单队列排队
                if (index < 0 || index >= _waitPointInfoList.Count)
                {
                    return null;
                }

                var waitInfo = _waitPointInfoList[index];
                var pointCfg = new CityRealAiEventPointConfig();
                pointCfg.eventId = eventId;
                pointCfg.Position = _waitPointPosList[index];
                pointCfg.Rotate = _waitPointRotList[index];
                waitInfo.UpdatePointCfg(ref pointCfg);
                return waitInfo;
            }
            else
            {
                // 多队列排队
                if (queueIndex < 0 || index < 0 || queueIndex >= _multiWaitPointVecPointInfoList.Count)
                {
                    return null;
                }

                var pointInfoList = _multiWaitPointVecPointInfoList[queueIndex];
                if (index >= pointInfoList.Count)
                {
                    return null;
                }
            
                var waitInfo = pointInfoList[index];
                var pointCfg = new CityRealAiEventPointConfig();
                pointCfg.eventId = eventId;
                pointCfg.Position = _multiWaitPointVecPosList[queueIndex][index];
                pointCfg.Rotate = _multiWaitPointVecRotList[queueIndex][index];
                waitInfo.UpdatePointCfg(ref pointCfg);
                return waitInfo;
            }
        }

        public override void AddNpcCtrl(CityRealAiNpcController npcCtrl)
        {
            base.AddNpcCtrl(npcCtrl);
            if (npcCtrl.NpcType == CityRealNpcType.AreaNpc)
            {
                _curAreaNpcNum++;
            }
            else if (npcCtrl.NpcType == CityRealNpcType.RoomNpc)
            {
                if (npcCtrl.BirthContainerId == ContainerId)
                {
                    RoomNpcNum++;
                }
            }
        }

        public CityRealAiNpcController GetNpcCtrl(int roleId, int uid)
        {
            if (NpcTypeCtrlDic.TryGetValue(roleId, out var npcCtrlDic))
            {
                if (npcCtrlDic.TryGetValue(uid, out var npcCtrl))
                {                
                    return npcCtrl;
                }
            }

            return null;
        }

        public CityRealAiNpcController GetNpcCtrlExcludeUid(int roleId, List<int> excludeUidList)
        {
            if (NpcTypeCtrlDic.TryGetValue(roleId, out var npcCtrlDic))
            {
                foreach (var keyValuePair in npcCtrlDic)
                {
                    if (excludeUidList==null || !excludeUidList.Contains(keyValuePair.Value.Uid))
                    {
                        return keyValuePair.Value;
                    }
                }
            }

            return null;
        }

        public override CityRealAiNpcController RemoveNpcCtrl(int roleId, int uid)
        {
            var npcCtrl = base.RemoveNpcCtrl(roleId, uid);
            if (npcCtrl == null)
            {
                return null;
            }
            if (npcCtrl.NpcType == CityRealNpcType.AreaNpc)
            {
                _curAreaNpcNum--;
                TriggerWaitQueueMove();
            }
            return npcCtrl;
        }

        public bool TryStartWaitQueue(CityRealAiNpcController npcCtrl, out int waitIndex, out int waitQueueIndex)
        {
            if (_waitPointInfoList.Count <= 0) // 无排队点
            {
                waitIndex = -1;
                waitQueueIndex = -1;
                return false;
            }

            if (_waitQueue.Count >= _waitPointInfoList.Count) // 排队人数已满
            {
                waitIndex = -1;
                waitQueueIndex = -1;
                return false;
            }
            
            waitIndex = _waitQueue.Count; // 占坑
            waitQueueIndex = -1;
            _waitQueue.Add(npcCtrl);
            return true;
        }

        public void TriggerWaitQueueMove()
        {
            if (_waitQueue.Count <= 0)
            {
                return;
            }
            
            var inMove = _waitQueue[0];
            _waitQueue.RemoveAt(0);
            inMove.WaitQueueComplete();
            var waitEnumer = _waitQueue.GetEnumerator();
            var waitIndex = 0;
            while (waitEnumer.MoveNext())
            {
                waitEnumer.Current.NextWaitQueue(waitIndex);
                waitIndex++;
            }
        }

        public void TriggerWaitQueueLeave(CityRealAiNpcController npcCtrl)
        {
            List<CityRealAiNpcController> waitQueue = null;
            if (npcCtrl.WaitQueueIndex >= 0)
            {
                // 多队列排队
                waitQueue = _multiWaitVecQueue[npcCtrl.WaitQueueIndex];
            }
            else
            {
                // 单队列排队
                waitQueue = _waitQueue;
            }

            if (waitQueue!=null && waitQueue.Count>0)
            {
                if (waitQueue.Remove(npcCtrl))
                {
                    // 如果移除的npc在队列中，则触发队列重新排序
                    var waitEnumer = waitQueue.GetEnumerator();
                    var waitIndex = 0;
                    while (waitEnumer.MoveNext())
                    {
                        waitEnumer.Current.NextWaitQueue(waitIndex);
                        waitIndex++;
                    }
                }
            }
        }
        
        /// <summary>
        /// 尝试获取多队列排队位置
        /// </summary>
        /// <param name="npcCtrl"></param>
        /// <param name="waitIndex"></param>
        /// <param name="waitQueueIndex"></param>
        /// <returns></returns>
        public bool TryStartMultiWaitQueue(CityRealAiNpcController npcCtrl, out int waitIndex, out int waitQueueIndex)
        {
            // 查找有空位的队伍
            List<int> waitQueueIndices = ListPool<int>.Get();
            for (int i = 0; i < _multiWaitVecQueue.Count; ++i)
            {
                if (_multiWaitVecQueue[i].Count < _multiWaitPointVecPointInfoList[i].Count)
                {
                    waitQueueIndices.Add(i);
                }
            }

            // 没有空闲队伍
            if (waitQueueIndices.Count <= 0)
            {
                ListPool<int>.Release(waitQueueIndices);
                waitIndex = -1;
                waitQueueIndex = -1;
                return false;
            }

            waitQueueIndex = Random.Range(0, waitQueueIndices.Count);
            waitIndex = _multiWaitVecQueue[waitQueueIndex].Count;
            
            // 查找人数最少的队伍
            foreach(int queueIndex in waitQueueIndices)
            {
                if (_multiWaitVecQueue[queueIndex].Count < waitIndex+1)
                {
                    waitQueueIndex = queueIndex;
                    waitIndex = _multiWaitVecQueue[waitQueueIndex].Count;
                }
            }
            
            // // TODO: 测试只有一队的情况
            // waitQueueIndex = 0;
            // waitIndex = _multiWaitVecQueue[waitQueueIndex].Count;
            
            _multiWaitVecQueue[waitQueueIndex].Add(npcCtrl);   // 占坑
            ListPool<int>.Release(waitQueueIndices);
            return true;
        }

        public void TriggerMultiWaitQueueMove(int waitQueueIndex)
        {
            if (_multiWaitVecQueue.Count <= waitQueueIndex || _multiWaitVecQueue[waitQueueIndex].Count < 0)
            {
                return;
            }
            
            // 弹出第一个npc
            var waitQueue = _multiWaitVecQueue[waitQueueIndex];
            waitQueue.RemoveAt(0);
            
            // 后面npc的向前移动
            var waitEnumer = waitQueue.GetEnumerator();
            var waitIndex = 0;
            while (waitEnumer.MoveNext())
            {
                waitEnumer.Current.NextWaitQueue(waitIndex);
                waitIndex++;
            }
        }

        public void StartSpecialStateTimer()
        {
            
            if (_isExistLecture)
            {
                StartLectureStateTimer();
            }
        }

        private void StartLectureStateTimer()
        {
           
            
            if (!Timers.inst.Exists(OnLectureStateInterval))
            {
                var cfgMgr = _cfgMgr;
                var timeRange = cfgMgr.GlobalCfg.cityRealAiTimeRange;
                var timeRandom = cfgMgr.GlobalCfg.cityRealAiTimeRandom;
                var timeStep = cfgMgr.GlobalCfg.cityRealAiTimeStep;
                var leftRange = (timeRange - timeRandom) / timeStep;
                var rightRange = (timeRandom + timeRandom) / timeStep + 1;
                var lectureStateTimeInterval = Mathf.Max(Random.Range(leftRange, rightRange) * timeStep, 1); // 最少间隔1秒
                Timers.inst.Add(lectureStateTimeInterval, 1, OnLectureStateInterval);
            }
        }

        private void OnLectureStateInterval(object param)
        {
            TriggerRoomStateChangeEvent(CityRealRoomStateChangeEvent.BeforeLecture);
        }

        public void TryTriggerRoomStateChange(string parameterKey, int uid)
        {
            if (_stateTriggerProcessParameterDic == null || _parameterKeyIndex == null) // 本房间没有特殊状态可以切换
            {
                return;
            }
            
            if (_parameterKeyIndex.TryGetValue(parameterKey, out var roomStateList))
            {
                for (int i = 0; i < roomStateList.Count; i++)
                {
                    var roomState = roomStateList[i];
                    if (_stateTriggerProcessParameterDic.TryGetValue(roomState, out var triggerProcessDic))
                    {
                        if (triggerProcessDic.TryGetValue(parameterKey, out var parameterInfo))
                        {
                            if (!parameterInfo.TriggerNpcUidList.Contains(uid))
                            {
                                parameterInfo.TriggerNpcUidList.Add(uid);
                            }
                        }

                        var isTriggerEvent = true;
                        foreach (var keyValuePair in triggerProcessDic)
                        {
                            if (keyValuePair.Key == CityRealAiConst.RoomParamaterStateTag)
                            {
                                var isInState = IsInState(keyValuePair.Value.ParameterValue);
                                if (isInState)
                                {
                                    continue;
                                }
                                isTriggerEvent = false; // 条件未满足，直接结束检测
                                break;
                            }
                            else
                            {
                                if (keyValuePair.Value.TriggerNpcUidList.Count >= keyValuePair.Value.ParameterValue)
                                {
                                    continue;
                                }
                                isTriggerEvent = false; // 条件未满足，直接结束检测
                                break;
                            }
                        }

                        if (isTriggerEvent)
                        {
                            foreach (var keyValuePair in triggerProcessDic)
                            {
                                keyValuePair.Value.TriggerNpcUidList.Clear();
                            }
                            TriggerRoomStateChangeEvent((CityRealRoomStateChangeEvent) roomState);
                        }
                    }
                }
            }
        }
        
        public virtual void TriggerRoomStateChangeEvent(CityRealRoomStateChangeEvent changeEvent)
        {
            // Debug.LogFormat(LogModule.CityAI, "房间 = {0} 内触发 事件 = {1}", LogLevelType.Develop, ContainerId, changeEvent);
            switch (changeEvent)
            {
                case CityRealRoomStateChangeEvent.StartUpgrade:
                    if (IsInState(CityRealRoomState.Upgrade))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Upgrade, true);
                    // TryTriggerRoomEvent(changeEvent, false);
                    // ForceNpcLeave();
                    break;
                case CityRealRoomStateChangeEvent.EndUpgrade:
                    if (!IsInState(CityRealRoomState.Upgrade))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Upgrade, false);
                    // ReStartRoomTypeNpc();
                    // TryCloseRoomEvent(CityRealRoomStateChangeEvent.StartUpgrade);
                    // TryTriggerRoomEvent(changeEvent, true);
                    break;
                case CityRealRoomStateChangeEvent.StartTrain:
                    if (IsInState(CityRealRoomState.Train))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Train, true);
                    TryTriggerRoomEvent(changeEvent, false);
                    break;
                case CityRealRoomStateChangeEvent.EndTrain:
                    if (!IsInState(CityRealRoomState.Train))
                    {
                        return;
                    }
                    TryCloseRoomEvent(CityRealRoomStateChangeEvent.EndTrain);
                    SetupState(CityRealRoomState.Train, false);
                    TryTriggerRoomEvent(changeEvent, true);
                    break;
                case CityRealRoomStateChangeEvent.StartTreat:
                    if (IsInState(CityRealRoomState.Treat))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Treat, true);
                    TryTriggerRoomEvent(changeEvent, false);
                    break;
                case CityRealRoomStateChangeEvent.EndTreat:
                    if (!IsInState(CityRealRoomState.Treat))
                    {
                        return;
                    }
                    TryCloseRoomEvent(CityRealRoomStateChangeEvent.StartTreat);
                    SetupState(CityRealRoomState.Treat, false);
                    if (IsInState(CityRealRoomState.Wounded))
                    {
                        TryTriggerRoomEvent(CityRealRoomStateChangeEvent.ExistWoundedSoldier, false);
                    }
                    else
                    {
                        TryTriggerRoomEvent(changeEvent, true);
                    }
                    break;
                case CityRealRoomStateChangeEvent.BeforeLecture:
                    SetupState(CityRealRoomState.Lecture, true);
                    TryTriggerRoomEvent(changeEvent, false);
                    break;
                case CityRealRoomStateChangeEvent.StartLecture:
                    TryTriggerRoomEvent(changeEvent, false);
                    break;
                case CityRealRoomStateChangeEvent.EndLecture:
                    TryCloseRoomEvent(CityRealRoomStateChangeEvent.BeforeLecture);
                    TryCloseRoomEvent(CityRealRoomStateChangeEvent.StartLecture);
                    SetupState(CityRealRoomState.Lecture, false);
                    TryTriggerRoomEvent(changeEvent, true);
                    StartLectureStateTimer();
                    break;
                case CityRealRoomStateChangeEvent.StartReinforce:
                    if (IsInState(CityRealRoomState.Reinforce))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Reinforce, true);
                    TryTriggerRoomEvent(changeEvent, false);
                    break;
                case CityRealRoomStateChangeEvent.EndReinforece:
                    if (!IsInState(CityRealRoomState.Reinforce))
                    {
                        return;
                    }
                    TryCloseRoomEvent(CityRealRoomStateChangeEvent.StartReinforce);
                    SetupState(CityRealRoomState.Reinforce, false);
                    TryTriggerRoomEvent(changeEvent, true);
                    break;
                case CityRealRoomStateChangeEvent.StartAssembly:
                    if (IsInState(CityRealRoomState.Assembly))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Assembly, true);
                    TryTriggerRoomEvent(changeEvent, false);
                    break;
                case CityRealRoomStateChangeEvent.EndAssembly:
                    if (!IsInState(CityRealRoomState.Assembly))
                    {
                        return;
                    }
                    TryCloseRoomEvent(CityRealRoomStateChangeEvent.StartAssembly);
                    SetupState(CityRealRoomState.Assembly, false);
                    TryTriggerRoomEvent(changeEvent, true);
                    break;
                case CityRealRoomStateChangeEvent.ExistWoundedSoldier:
                    if (IsInState(CityRealRoomState.Wounded))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Wounded, true);
                    if (IsInState(CityRealRoomState.Treat))
                    {
                        return;
                    }
                    TryTriggerRoomEvent(changeEvent, false);
                    break;
                case CityRealRoomStateChangeEvent.NotWoundedSoldier:
                    if (!IsInState(CityRealRoomState.Wounded))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Wounded, false);
                    if (IsInState(CityRealRoomState.Treat))
                    {
                        return;
                    }
                    TryCloseRoomEvent(CityRealRoomStateChangeEvent.ExistWoundedSoldier);
                    TryTriggerRoomEvent(changeEvent, true);
                    break;
                case CityRealRoomStateChangeEvent.StartResearch:
                    if (IsInState(CityRealRoomState.Research))
                    {
                        return;
                    }
                    SetupState(CityRealRoomState.Research, true);
                    TryTriggerRoomEvent(changeEvent, false);
                    break;
                case CityRealRoomStateChangeEvent.EndResearch:
                    SetupState(CityRealRoomState.Research, false);
                    TryCloseRoomEvent(CityRealRoomStateChangeEvent.StartResearch);
                    TryTriggerRoomEvent(changeEvent, true);
                    break;
            }
        }

        private void TryTriggerRoomEvent(CityRealRoomStateChangeEvent eventId, bool isEndEvent)
        {
            if (_roomCommonEventConfigDic != null)
            {
                foreach (var keyValuePair in _roomCommonEventConfigDic)
                {
                    var roomEvent = keyValuePair.Value;
                    if (roomEvent.room_state == (int) eventId)
                    {
                        TriggerRoomEvent(eventId, ref roomEvent, isEndEvent);
                        return;
                    }
                }
            }

            if (_roomEventConfigDic != null)
            {
                foreach (var keyValuePair in _roomEventConfigDic)
                {
                    var roomEvent = keyValuePair.Value;
                    if (roomEvent.room_state == (int) eventId)
                    {
                        TriggerRoomEvent(eventId, ref roomEvent, isEndEvent);
                        return;
                    }
                }
            }
        }
        
        private void TriggerRoomEvent(CityRealRoomStateChangeEvent eventId, ref CityRealAiRoomEventConfig roomEventConfig, bool isEndEvent)
        {
            if (roomEventConfig.ex_event_type == (int) CityRealRoomEventExecuteType.Immediately) // 立即获取足够的NPC开始集体事件，否则就执行失败！
            {
                var success = false;
                var npcList = new List<List<CityRealAiNpcController>>();
                for (int i = 0; i < roomEventConfig.link_npc.Length; i++)
                {
                    var npcCfg =  roomEventConfig.link_npc[i];
                    var npcTree = roomEventConfig.ex_event_tree[i];
                    var tempList = new List<CityRealAiNpcController>();
                    success = GetImmediatelyTriggerRoomEventNpcCtrlList(npcCfg, (int) npcTree.x, (int)npcCfg.z, tempList, npcList);
                    if (!success)
                    {
                        var areaDic = CityRealAiManager.GetInstance().AreaDic; // 跨区域寻找小人
                        foreach (var keyValuePair in areaDic)
                        {
                            var area = keyValuePair.Value;
                            success = area.GetImmediatelyTriggerRoomEventNpcCtrlList(npcCfg, (int) npcTree.x, ((int)npcCfg.z - npcList.Count), tempList, npcList);
                            if (success)
                            {
                                break;
                            }
                        }
                    }
                    if (success)
                    {
                        npcList.Add(tempList);
                    }
                    else // 获取失败，无法执行逻辑
                    {
                        break;
                    }
                }

                if (success) // NPC获取成功，立即执行房间事件！
                {
                    var eventInfo = new CityRealAiRoomEventInfo(roomEventConfig);
                    eventInfo.UpdateImmediatelyPerformerList(npcList);
                    int delayIndex = 0;
                    for (int i = 0; i < eventInfo.PerformerList.Count; i++)
                    {
                        var npcCtrls = eventInfo.PerformerList[i];
                        var eventTreeInfos = eventInfo.LinkNpcInfoList[i];
                        for (int j = 0; j < npcCtrls.Count; j++)
                        {
                            var npcCtrl = npcCtrls[j];
                            var eventTree = eventTreeInfos[j];
                            
                            var treeConfig = _cfgMgr.GetAiEventTreeConfig((int) eventTree.x);
                            var treeType = isEndEvent ? CityRealEventTreeType.SpecialEndEventTree : CityRealEventTreeType.SpecialEventTree;
                            float delayTime = 0;
                            if (!npcCtrl.IsAlive) // 房间特殊事件，Npc处于隐藏状态时，需要间隔显示
                            {
                                delayTime = delayIndex * 1;
                                delayIndex++;
                            }
                            npcCtrl.ImmediatelyExecuteEventTree(treeConfig, treeType, ContainerId, BuildIndex, (int) eventTree.y, delayTime);
                        }
                    }
                    if (isEndEvent)
                    {
                        eventInfo.OnDipose(); // 结束事件，不应该存在loop事件，这里不缓存，直接曲终人散。
                    }
                    else
                    {
                        if (!_currentRoomEventDic.TryGetValue(eventId, out var eventInfoDic))
                        {
                            eventInfoDic = new Dictionary<int, CityRealAiRoomEventInfo>();
                            _currentRoomEventDic.Add(eventId, eventInfoDic);
                        }
                        eventInfoDic.Add(eventInfoDic.Count, eventInfo);
                    }
                }
            }
            else if (roomEventConfig.ex_event_type == (int)CityRealRoomEventExecuteType.Wait) // 等待NPC主动过来执行集体事件。
            {
                if (isEndEvent) // 结束事件，理论上是驱散人群的，所以是必须立即执行。
                {
                    return;
                }
                var eventInfo = new CityRealAiRoomEventInfo(roomEventConfig);
                eventInfo.UpdateWaitPerformerList();
                if (!_currentRoomEventDic.TryGetValue(eventId, out var eventInfoDic))
                {
                    eventInfoDic = new Dictionary<int, CityRealAiRoomEventInfo>();
                    _currentRoomEventDic.Add(eventId, eventInfoDic);
                }
                eventInfoDic.Add(eventInfoDic.Count, eventInfo);
            }
        }

        public override bool CheckNeedAndRunNpc(CityRealAiNpcController npcCtrl)
        {
            if (_currentRoomEventDic == null || _currentRoomEventDic.Count <= 0)
            {
                return false;
            }

            foreach (var keyValuePair in _currentRoomEventDic)
            {
                foreach (var subKeyValue in keyValuePair.Value)
                {
                    var roomEventInfo = subKeyValue.Value;
                    if (roomEventInfo.RoomEventConfig.ex_event_type == (int)CityRealRoomEventExecuteType.Immediately)
                    {
                        continue;
                    }

                    if (!roomEventInfo.IsNeedNpc)
                    {
                        continue;
                    }

                    if (roomEventInfo.CheckNeedAndGetNpcInfo(npcCtrl, out var linkNpcInfo))
                    {
                        var treeConfig = _cfgMgr.GetAiEventTreeConfig((int) linkNpcInfo.x);
                        npcCtrl.ImmediatelyExecuteEventTree(treeConfig, CityRealEventTreeType.SpecialEventTree, ContainerId, BuildIndex, (int) linkNpcInfo.y);
                        roomEventInfo.UpdateIsNeedNpc();
                        return true;
                    }
                }
            }

            return false;
        }

        private void TryCloseRoomEvent(CityRealRoomStateChangeEvent eventId)
        {
            if (_currentRoomEventDic == null)
            {
                return;
            }
            
            if (_currentRoomEventDic.TryGetValue(eventId, out var eventInfoDic))
            {
                foreach (var keyValuePair in eventInfoDic)
                {
                    for (int i = 0; i < keyValuePair.Value.PerformerList.Count; i++)
                    {
                        var npcCtrlList = keyValuePair.Value.PerformerList[i];
                        for (int j = 0; j < npcCtrlList.Count; j++)
                        {
                            var npcCtrl = npcCtrlList[j];
                            npcCtrl.ImmediatelyCloseEventTree();
                        }
                    }
                    keyValuePair.Value.OnDipose();
                }
                _currentRoomEventDic.Remove(eventId);
            }
        }

        public void AddMoveToSelfNpc(CityRealAiNpcController npcCtrl)
        {
            if (_moveToSelfList == null)
            {
                _moveToSelfList = new List<CityRealAiNpcController>();
            }
            
            _moveToSelfList.Add(npcCtrl);
        }

        public void RemoveMoveToSelfNpc(CityRealAiNpcController npcCtrl)
        {
            if (_moveToSelfList == null)
            {
                return;
            }
            
            _moveToSelfList.Remove(npcCtrl);
        }
        
        public void OnReStartRoomAllNpc()
        {
            IsDragState = false;
            bool isExistUpgradeNpc = false;
            bool isInUpgrade = IsInState(CityRealRoomState.Upgrade);
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var npcCtrl = subKeyValuePair.Value;
                    if (npcCtrl.RoleTag == CityRealAiConst.UpgradeNpcTag)
                    {
                        isExistUpgradeNpc = true;
                        npcCtrl.OnPause(false);
                    }
                    // else if (isInUpgrade && npcCtrl.NpcType == CityRealNpcType.AreaNpc) // 升级驱散过程中，改变房子位置，则重启区域NPC，让其走出房间。
                    // {
                    //     npcCtrl.OnPause(false);
                    // }
                    else
                    {
                        npcCtrl.OnPause(false);
                    }
                }
            }

            if (!isExistUpgradeNpc && isInUpgrade) // 升级NPC小人还未到房间，需要Call过来。
            {
                var updrageEvent = CityRealRoomStateChangeEvent.StartUpgrade;
                
                _currentRoomEventDic.Remove(updrageEvent); // 丢弃之前的升级事件数据，重新触发
                TryTriggerRoomEvent(updrageEvent, false);
            }
        }

        private void ReStartRoomTypeNpc()
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var npcCtrl = subKeyValuePair.Value;
                    if (npcCtrl.NpcType == CityRealNpcType.RoomNpc)
                    {
                        npcCtrl.OnPause(false);
                    };
                }
            }
        }

        private void ForceNpcLeave()
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var npcCtrl = subKeyValuePair.Value;
                    if (npcCtrl.NpcType == CityRealNpcType.AreaNpc)
                    {
                        npcCtrl.EndEventTree();
                        npcCtrl.TryExecuteEventTree(ContainerId);
                    }
                    else if (npcCtrl.NpcType == CityRealNpcType.RoomNpc && npcCtrl.RoleTag != CityRealAiConst.UpgradeNpcTag)
                    {
                        npcCtrl.OnPause(true);
                    }
                }
            }
            
            ForceBreakMoveToSelfNpc();
        }
        
        public void OnStopRoomAllNpc()
        {
            IsDragState = true;
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var npcCtrl = subKeyValuePair.Value;
                    npcCtrl.OnPause(true);
                }
            }

            ForceBreakMoveToSelfNpc();
        }

        private void ForceBreakMoveToSelfNpc()
        {
            for (int i = 0; i < _moveToSelfList.Count; i++)
            {
                var npcCtrl = _moveToSelfList[i];
                npcCtrl.EndEventTree();
                npcCtrl.TryExecuteEventTree(ContainerId);
            }
            _moveToSelfList.Clear();
            
            for(int i=_waitQueue.Count-1; i>=0; --i)   // WARH-18414: 顾客会离开队伍，所以这里不能用foreach遍历
            {
                var npcCtrl = _waitQueue[i];
                npcCtrl.EndEventTree();
                npcCtrl.TryExecuteEventTree(ContainerId);
            }
            _waitQueue.Clear();
        }

        public void ShowOrHideAllNpc(bool state)
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                var cityRealAiNpcControllers = keyValuePair.Value;
                foreach (var subKeyValuePair in cityRealAiNpcControllers)
                {
                    var cityRealAiNpcController = subKeyValuePair.Value;
                    cityRealAiNpcController.ShowOrHide(state);

                    // 区域1的小人会开门营业，不能暂停，其他区域的小人可以停掉逻辑
                    if (AreaId != 1)
                        cityRealAiNpcController.OnPause(!state);
                }
            }
        }

        public bool IsInState(CityRealRoomState stateType)
        {
            return IsInState((int)stateType);
        }

        public bool IsInState(int stateType)
        {
            var intStateType = stateType;
            return (_roomState & intStateType) == intStateType; 
        }

        public void SetupState(CityRealRoomState stateType, bool value)
        {
            var intStateType = (int)stateType;
            _roomState = value ? (_roomState | intStateType) : (_roomState & ~intStateType);
        }

        #region  构建房间内PointGraph

        

        #endregion
        public void SetupScanPointGraph()
        {
            if (_movePointNodeList.Count > 0) // 已经设置好了
            {
                return;
            }
            
            if (AstarPath.active)
            {
                var pointGraph = AstarPath.active.data.pointGraph;
                pointGraph.OnScanGraph += AddPointGraph;
            }
        }

        private void AddPointGraph()
        {
            if (_movePointNodeList.Count > 0)
            {
                return;
            }
            
            var pointGraph = AstarPath.active.data.pointGraph;
            var groupIndex = ContainerId * 100 + BuildIndex;
            for (int i = 0; i < _movePointLocalPosList.Count; i++)
            {
#if UNITY_EDITOR
                var point = new GameObject($"movePoint_{i}");
                point.SetParent(RoomRootTran);
                point.transform.position = GetWorldPos(_movePointLocalPosList[i]);
                _movePointNodeList.Add(pointGraph.AddNodeInternal(point.transform, groupIndex));
#else
                _movePointNodeList.Add(pointGraph.AddNodeInternal(GetWorldPos(_movePointLocalPosList[i]), groupIndex));
#endif
            }
            pointGraph.OnScanGraph -= AddPointGraph;
        }

        public void UpdateNavPointsPosition()
        {
            for (int i = 0; i < _movePointNodeList.Count; i++)
            {
                PointNode pointNode = _movePointNodeList[i];
                pointNode.position = (Int3) GetWorldPos(_movePointLocalPosList[i]);
                pointNode.needUpdate = true;
                pointNode.Walkable = true;
                pointNode.needReInit = true;
            }
            
        }
        public override void OnCloseBusiness()
        {
            _jumpToRoomPointIndex = 0;
            for (int i = 0; i < _cacheRubbishList.Count; i++)
            {
                HideRubbish(_cacheRubbishList[i].Owner.Uid);
            }

            for (int i = 0; i < _cacheFixList.Count; i++)
            {
                HideFix(_cacheFixList[i].Owner.Uid);
            }
        }

        public override void OnResetNpc()
        {
            if (Timers.inst.Exists(OnLectureStateInterval))
            {
                Timers.inst.Remove(OnLectureStateInterval);
            }
            base.OnResetNpc();
            _roomState = 0;
            _curAreaNpcNum = 0;
            if (_currentRoomEventDic != null)
            {
                _currentRoomEventDic.Clear();
            }
            if (_stateTriggerProcessParameterDic != null)
            {
                foreach (var keyValuePair in _stateTriggerProcessParameterDic)
                {
                    foreach (var subKeyValuePair in keyValuePair.Value)
                    {
                        subKeyValuePair.Value.TriggerNpcUidList.Clear();
                    }
                }
            }
            _waitQueue.Clear();
            foreach (var waitQueue in _multiWaitVecQueue)
            {
                waitQueue.Clear();
            }
        }
        
        public override void OnUpdate()
        {
            base.OnUpdate();
            if (CityRealAiConst.IsInOpenBusiness && ContainerId == CityRealAiConst.HallId)
            {
                CheckRubbishEvent();
                CheckFixEvent();
            }
        }

        private int _checkRubbishIndex = 0;

        /// <summary>
        /// 检查生成垃圾事件
        /// </summary>
        private void CheckRubbishEvent()
        {
            _checkRubbishIndex++;
            if (_checkRubbishIndex <= _cfgMgr.GlobalCfg.city_operate_rubbish_pertime)
            {
                return;
            }

            _checkRubbishIndex = 0;
            if (_cacheRubbishList.IsEmpty())
            {
                return;
            }
            
            var rubbishCfg = _cfgMgr.GetOperateInteractiveConfig(CityRealAiConst.RubbishGoodsCfgId);
            if (rubbishCfg.id == _cfgMgr.EmptyOperateInteractiveConfig.id)
            {
                return;
            }

            var random = Random.Range(0, 100);
            if (random > _cfgMgr.GlobalCfg.city_operate_rubbish_trigger_basepro) // 随机未通过
            {
                return;
            }

            var randomList = ListPool<int>.Get();
            var existCount = 0;
            for (int i = 0; i < _cacheRubbishList.Count; i++)
            {
                var eventCfg = _cacheRubbishList[i];
                var owner = eventCfg.Owner;
                if (owner == null)
                {
                    continue;
                }
                var existMoveGoods = owner.CheckExistMoveGoods(eventCfg.PointConfig.MoveGoodsName, owner.Uid, eventCfg.EventId, CityRealEventPointState.Idle);
                if (existMoveGoods)
                {
                    existCount += 1;
                }
                else
                {
                    randomList.Add(i);
                }
            }

            if (existCount >= _cfgMgr.GlobalCfg.city_operate_rubbish_limit) // 当前垃圾已经达到上限
            {
                ListPool<int>.Release(randomList);
                return;
            }

            var randomIndex = Random.Range(0, randomList.Count);
            var randomEventInfo = _cacheRubbishList[randomList[randomIndex]];
            ListPool<int>.Release(randomList);
            
            GameObjectPoolManager.GetInstance().Pop(rubbishCfg.prefab, delegate(GameObject rubbish)
            {
                var owner = randomEventInfo.Owner;
                var moveGoodsIndex = owner.OnUpdateMoveGoods(randomEventInfo.PointConfig.MoveGoodsName, rubbish);
                if (moveGoodsIndex >= 0)
                {
#if UNITY_EDITOR
                    rubbish.name = randomEventInfo.PointConfig.MoveGoodsName;
#endif
                    rubbish.SetParent(RoomRootTran, true);
                    rubbish.transform.localPosition = randomEventInfo.PointConfig.MoveGoodsPosList[moveGoodsIndex];
                    rubbish.transform.localEulerAngles = randomEventInfo.PointConfig.MoveGoodsRotList[moveGoodsIndex];
                    var goodsRotateMono = rubbish.GetComponentInChildren<CityRealMoveGoodsMono>();
                    if (goodsRotateMono != null)
                    {
                        goodsRotateMono.ChangeNodeRotate(true);
                    }
                    CityRealAiManager.GetInstance().HudMgr.OnShowCommodity(owner.Uid, CityRealAiConst.CommodityBubbleRubbish, rubbish.transform, CityRealAiConst.RubbishBubbleBone, rubbishCfg.bubble_id);
                }
            });
        }

        public void HideRubbish(int uid, float duration = 0)
        {
            for (int i = 0; i < _cacheRubbishList.Count; i++)
            {
                var eventPointInfo = _cacheRubbishList[i];
                if (eventPointInfo.Owner != null && eventPointInfo.Owner.Uid == uid)
                {
                    var rubbishObj = eventPointInfo.Owner.GetMoveGoods(eventPointInfo.PointConfig.MoveGoodsName);
                    if (rubbishObj != null)
                    {
                        var rubbishCfg = _cfgMgr.GetOperateInteractiveConfig(CityRealAiConst.RubbishGoodsCfgId);
                        Timers.inst.Add(duration, 1, delegate
                        {
                            if (_cacheRubbishList == null)
                            {
                                GameObject.Destroy(rubbishObj);
                                return;
                            }
                            GameObjectPoolManager.GetInstance().Push(rubbishCfg.prefab, rubbishObj);
                        });
                        CityRealAiManager.GetInstance().HudMgr.PlayProgressAndHideCommodityBubble(uid, duration);
                    }

                    var performer = eventPointInfo.Performer;
                    if (performer != null)
                    {
                        performer.EndEventTree();
                        performer.TryExecuteEventTree();
                    }
                    break;
                }
            }
            
        }

        private int _checkFixIndex = 0;

        /// <summary>
        /// 检查生成设施损坏事件
        /// </summary>
        private void CheckFixEvent()
        {
            _checkFixIndex++;
            if (_checkFixIndex <= _cfgMgr.GlobalCfg.city_operate_fix_pertime)
            {
                return;
            }

            _checkFixIndex = 0;
            if (_cacheFixList.IsEmpty())
            {
                return;
            }
            
            var fixCfg = _cfgMgr.GetOperateInteractiveConfig(CityRealAiConst.FixGoodsCfgId);
            if (fixCfg.id == _cfgMgr.EmptyOperateInteractiveConfig.id)
            {
                return;
            }
            
            var random = Random.Range(0, 100);
            if (random > _cfgMgr.GlobalCfg.city_operate_fix_trigger_basepro) // 随机未通过
            {
                return;
            }
            
            var randomList = ListPool<int>.Get();
            var existCount = 0;
            for (int i = 0; i < _cacheFixList.Count; i++)
            {
                var eventCfg = _cacheFixList[i];
                var owner = eventCfg.Owner;
                if (owner == null)
                {
                    continue;
                }
                var existMoveGoods = owner.CheckExistMoveGoods(eventCfg.PointConfig.MoveGoodsName, owner.Uid, eventCfg.EventId, CityRealEventPointState.Idle);
                if (existMoveGoods)
                {
                    existCount += 1;
                }
                else
                {
                    randomList.Add(i);
                }
            }

            if (existCount >= _cfgMgr.GlobalCfg.city_operate_fix_limit) // 当前修理气泡已经达到上限
            {
                ListPool<int>.Release(randomList);
                return;
            }
            
            // 找一个空位，填充垃圾堆。
            var randomIndex = Random.Range(0, randomList.Count);
            var randomEventInfo = _cacheFixList[randomList[randomIndex]];
            ListPool<int>.Release(randomList);
            
            GameObjectPoolManager.GetInstance().Pop(fixCfg.prefab, delegate(GameObject fix)
            {
                var owner = randomEventInfo.Owner;
                var moveGoodsIndex = owner.OnUpdateMoveGoods(randomEventInfo.PointConfig.MoveGoodsName, fix);
                if (moveGoodsIndex >= 0)
                {
#if UNITY_EDITOR
                    fix.name = randomEventInfo.PointConfig.MoveGoodsName;
#endif
                    fix.SetParent(RoomRootTran, true);
                    fix.transform.localPosition = randomEventInfo.PointConfig.MoveGoodsPosList[moveGoodsIndex];
                    fix.transform.localEulerAngles = randomEventInfo.PointConfig.MoveGoodsRotList[moveGoodsIndex];
                    var goodsRotateMono = fix.GetComponentInChildren<CityRealMoveGoodsMono>();
                    if (goodsRotateMono != null)
                    {
                        goodsRotateMono.ChangeNodeRotate(true);
                    }
                    CityRealAiManager.GetInstance().HudMgr.OnShowCommodity(owner.Uid, CityRealAiConst.CommodityBubbleFix, fix.transform, CityRealAiConst.FixBubbleBone, fixCfg.bubble_id);
                }
            });
        }

        public void HideFix(int uid, float duration = 0)
        {
            for (int i = 0; i < _cacheFixList.Count; i++)
            {
                var eventPointInfo = _cacheFixList[i];
                if (eventPointInfo.Owner != null && eventPointInfo.Owner.Uid == uid)
                {
                    var fixObj = eventPointInfo.Owner.GetMoveGoods(eventPointInfo.PointConfig.MoveGoodsName);
                    if (fixObj != null)
                    {
                        var fixCfg = _cfgMgr.GetOperateInteractiveConfig(CityRealAiConst.FixGoodsCfgId);
                        Timers.inst.Add(duration, 1, delegate
                        {
                            if (_cacheFixList == null)
                            {
                                GameObject.Destroy(fixObj);
                                return;
                            }
                            GameObjectPoolManager.GetInstance().Push(fixCfg.prefab, fixObj);
                        });
                        CityRealAiManager.GetInstance().HudMgr.PlayProgressAndHideCommodityBubble(uid, duration);
                    }

                    var performer = eventPointInfo.Performer;
                    if (performer != null)
                    {
                        performer.EndEventTree();
                        performer.TryExecuteEventTree();
                    }
                    break;
                }
            }
        }

        public void StopAllBabeMoodHud()
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var npcCtrl = subKeyValuePair.Value;
                    if (npcCtrl.RoleClassType == (int)CityRealNpcClassType.Babe)
                    {
                        CityRealAiManager.GetInstance().HudMgr.OnStopBabeMood(npcCtrl.Uid);
                    }
                }
            }
        }

        public void RefreshAllBabeMoodHud()
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var npcCtrl = subKeyValuePair.Value;
                    if (npcCtrl.RoleClassType == (int)CityRealNpcClassType.Babe)
                    {
                        npcCtrl.ResetTimestamp();
                    }
                }
            }
        }

        public GameObject GetBabeMoodHudById(int roleId)
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var npcCtrl = subKeyValuePair.Value;
                    if (npcCtrl.RoleClassType==(int)CityRealNpcClassType.Babe && npcCtrl.RoleId == roleId)
                    {
                        if (CityRealAiManager.GetInstance().HudMgr.BabeMoodDic.TryGetValue(npcCtrl.Uid, out var hud))
                        {
                            return hud.GetHudObj();;
                        }
                        break;
                    }
                    
                }
            }

            return null;
        }

        public override void Dispose()
        {
            if (Timers.inst.Exists(OnLectureStateInterval))
            {
                Timers.inst.Remove(OnLectureStateInterval);
            }

            if (_cacheRubbishList != null)
            {
                _cacheRubbishList.Clear();
                _cacheRubbishList = null;
            }
            if (_cacheFixList != null)
            {
                _cacheFixList.Clear();
                _cacheFixList = null;
            }
            
            base.Dispose();
            _roomState = 0;
            _curAreaNpcNum = 0;

            if (_roomCommonEventConfigDic != null)
            {
                _roomCommonEventConfigDic.Clear();
                _roomCommonEventConfigDic = null;
            }

            if (_roomEventConfigDic != null)
            {
                _roomEventConfigDic.Clear();
                _roomEventConfigDic = null;
            }
            
            if (_currentRoomEventDic != null)
            {
                _currentRoomEventDic.Clear();
                _currentRoomEventDic = null;
            }
            
            if (_stateTriggerProcessParameterDic != null)
            {
                _stateTriggerProcessParameterDic.Clear();
                _stateTriggerProcessParameterDic = null;
            }

            if (_parameterKeyIndex != null)
            {
                _parameterKeyIndex.Clear();
                _parameterKeyIndex = null;
            }

            if (_movePointLocalPosList != null)
            {
                _movePointLocalPosList.Clear();
                _movePointLocalPosList = null;
            }

            if (_movePointNodeList != null)
            {
                _movePointNodeList.Clear();
                _movePointNodeList = null;
            }

            if (_birthPointLocalPosList != null)
            {
                _birthPointLocalPosList.Clear();
                _birthPointLocalPosList = null;
            }

            if (_moveToSelfList != null)
            {
                _moveToSelfList.Clear();
                _moveToSelfList = null;
            }

            if (_waitQueue != null)
            {
                _waitQueue.Clear();
                _waitQueue = null;
            }

            if (_waitPointInfoList != null)
            {
                for (int i = 0; i < _waitPointInfoList.Count; i++)
                {
                    _waitPointInfoList[i].Reset();
                }
                _waitPointInfoList.Clear();
                _waitPointInfoList = null;
            }

            if (_waitPointPosList != null)
            {
                _waitPointPosList.Clear();
                _waitPointPosList = null;
            }
        }
    }
}
